package org.fle4y.common.utils.basic;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.fle4y.common.constants.common.MoneyConstant;


/**
 * author : xiehui<br>
 * company : northking <br>
 * Create at: 2012-5-31
 * @version : 1.0<br>
 *
 *  Description : 和Money相关的工具类
 */
public class MoneyUtil {
	/**
	 * 支持简体中文'一二'等字样

	 */
	private static boolean supportSimpleChineseDig = false;

	/**
	 * 当有元但和角之间有跳位时允许加零
	 */
	private static boolean canZeroBetweenYuanAndJiaoWhenSkip = true;

	/**
	 * 允许拾xx打头
	 */
	private static boolean supportShixx = false;
	/**
	 * 支持简体中文'一二'等字样
	 * @param SUPPORT_SIMPLE_CHINESE_DIG
	 */
	public static void setSupportSimpleChinese(boolean SUPPORT_SIMPLE_CHINESE_DIG) {
		MoneyUtil.supportSimpleChineseDig = SUPPORT_SIMPLE_CHINESE_DIG;
		initUnitMap();
		initDigitMap();
		initMarks();
	}
	/**
	 * 金额转换成中文大写
	 * @param amount
	 * @return
	 */
	public static String getAmountChn(String currencyDigits) {
		double MAXIMUM_NUMBER = 99999999999.99;
		
		String CN_ZERO = "\u96f6";
		String CN_ONE = "\u58f9";
		String CN_TWO = "\u8d30";
		String CN_THREE = "\u53c1";
		String CN_FOUR = "\u8086";
		String CN_FIVE = "\u4f0d";
		String CN_SIX = "\u9646";
		String CN_SEVEN = "\u67d2";
		String CN_EIGHT = "\u634c";
		String CN_NINE = "\u7396";
		String CN_TEN = "\u62fe";
		String CN_HUNDRED = "\u4f70";
		String CN_THOUSAND = "\u4edf";
		String CN_TEN_THOUSAND = "\u4e07";
		String CN_HUNDRED_MILLION = "\u4ebf";
		String CN_SYMBOL = "";// "人民币";
		String CN_DOLLAR = "\u5143";
		String CN_TEN_CENT = "\u89d2";
		String CN_CENT = "\u5206";
		String CN_INTEGER = "\u6574";

		String integral; 
		String decimal; 
		String outputCharacters = ""; 
		String[] parts;
		String[] digits, radices, bigRadices, decimals;
		int zeroCount;
		int i, p;
		String d;
		int quotient, modulus;

		try {
			currencyDigits = MoneyConstant.currentFormateTwo(currencyDigits.toString());
			if ("".equals(currencyDigits)) {
				return "";
			}
			if (!StringUtil.isMoney(currencyDigits)) {
				return currencyDigits;
			}

			if (Double.parseDouble(currencyDigits) > MAXIMUM_NUMBER) {
				return "";
			}
			if (currencyDigits.indexOf(".") == 0 || currencyDigits.indexOf(".") == currencyDigits.length() - 1)
				return currencyDigits;

			parts = currencyDigits.split("\\.");
			if (parts.length >= 1) {
				integral = parts[0];
				decimal = parts[1];

				if (decimal.length() > 2)
					decimal = decimal.substring(0, 2);
			} else {
				integral = currencyDigits;
				decimal = "";
			}
	
			digits = new String[] { CN_ZERO, CN_ONE, CN_TWO, CN_THREE, CN_FOUR, CN_FIVE, CN_SIX, CN_SEVEN, CN_EIGHT,
					CN_NINE };
			radices = new String[] { "", CN_TEN, CN_HUNDRED, CN_THOUSAND };
			bigRadices = new String[] { "", CN_TEN_THOUSAND, CN_HUNDRED_MILLION };
			decimals = new String[] { CN_TEN_CENT, CN_CENT };

			outputCharacters = "";
	
			if (Double.parseDouble(integral) > 0) {
				zeroCount = 0;
				for (i = 0; i < integral.length(); i++) {
					p = integral.length() - i - 1;
					d = integral.substring(i, i + 1);
					quotient = p / 4;
					modulus = p % 4;
					if (d.equalsIgnoreCase("0")) {
						zeroCount++;
					} else {
						if (zeroCount > 0) {
							outputCharacters += digits[0];
						}
						zeroCount = 0;
						outputCharacters += digits[Integer.parseInt(d)] + radices[modulus];
					}
					if (modulus == 0 && zeroCount < 4) {
						outputCharacters += bigRadices[quotient];
					}
				}
				outputCharacters += CN_DOLLAR;
			}

			if (!decimal.equalsIgnoreCase("") && !decimal.equalsIgnoreCase("00") && !decimal.equalsIgnoreCase("0")) {
				for (i = 0; i < decimal.length(); i++) {
					d = decimal.substring(i, i + 1);
					if (i == 0) {
						outputCharacters += digits[Integer.parseInt(d)];
						if (!d.equalsIgnoreCase("0")) {
							outputCharacters += decimals[i];
						}
					}
					if (i == 1) {
						if (!d.equalsIgnoreCase("0")) {
							outputCharacters += digits[Integer.parseInt(d)] + decimals[i];
						}
					}
				}
			}
			if ("".equals(outputCharacters)) {
				outputCharacters = CN_ZERO + CN_DOLLAR;
			}
			if (decimal.equalsIgnoreCase("") || decimal.equalsIgnoreCase("00") || decimal.equalsIgnoreCase("0")
					|| (decimal.length() == 2 && decimal.substring(1, 1).equalsIgnoreCase("0"))) {
				outputCharacters += CN_INTEGER;
			}
			outputCharacters = CN_SYMBOL + outputCharacters;
		} catch (NumberFormatException e) {
			e.printStackTrace();
			return currencyDigits;
		}
		return outputCharacters;
	}
	/**
	 * 大写金额转换为小写金额 Description:
	 * 
	 * @param moneyCap
	 * @return :
	 * @throws Exception
	 */
	public static String rmbBigToSmall(String moneyCap) throws Exception {
		if (moneyCap == null || moneyCap.trim().length() == 0) {
			return null;
		}
		moneyCap = moneyCap.replaceAll("億", "亿").replaceAll("貮", "贰").replaceAll("陸", "陆").replaceAll("萬", "万")
				.replaceAll("圆", "元").replaceAll("圓", "元").replaceAll("貳", "贰").replaceAll("正", "整").replaceAll("叄",
						"叁");
		if ("零元正".equals(moneyCap) || "零元整".equals(moneyCap)) {
			return "0";
		}
		if (moneyCap.startsWith("零")) {
			throw new Exception("错误的大写金额格式:起始'零'字样非法");
		}
		if (moneyCap.endsWith("零")) {
			throw new Exception("错误的大写金额格式:末尾'零'字样非法");
		}
		int yuanidx = moneyCap.indexOf("元");
		if (yuanidx != -1) {
			if (moneyCap.indexOf("元", yuanidx + 1) != -1) {
				throw new Exception("错误的大写金额格式:两个'元'字样");
			}
		}
		for (String invalidWord : invalidWords) {
			if (moneyCap.indexOf(invalidWord) != -1) {
				throw new Exception("错误的大写金额格式:'" + invalidWord + "'字样非法");
			}
		}
		int idxY = moneyCap.indexOf("元");
		int idxJ = moneyCap.indexOf("角");
		if (idxY != -1 && idxJ - idxY > 2 && (!canZeroBetweenYuanAndJiaoWhenSkip)) {
			throw new Exception("错误的大写金额格式:元和角之间不应该有零");
		}
		moneyCap = moneyCap.replaceAll(" ", moneyCap);
		Integer curUnit = null;
		Integer curNum = null;
		boolean hazPreZero = false;
		List<Bit> bits = new ArrayList<Bit>();
		// 解析各位：


		for (int i = 0; i < moneyCap.length(); i++) {
			String c = null;
			for (String mark : marks) {
				if (moneyCap.indexOf(mark, i) == i) {
					c = mark;
					break;
				}
			}
			if (c == null) {
				char charAt = moneyCap.charAt(i);
				if (isWholeMarkAtEnd(moneyCap, i, charAt)) {
					break;
				} else if ('零' == charAt) {
					hazPreZero = true;
					continue;
				} else {
					throw new Exception("错误的大写金额，字符'" + charAt + "'非法！");
				}
			}
			i += c.length() - 1;

			Integer unit = unitMap.get(c);
			if (unit != null) {
				if (curUnit != null) {
					if (unit == 0) {
						// 万元、亿元等是许可的
						continue;
					} else {
						throw new Exception("错误的大写金额格式，连续两个单位！");
					}
				} else {

					if (curNum == null) {
						if (supportShixx && ((unit == 1 && i == 0) || ((unit == 9 || unit == 5) && i == 1)

						|| ((unit == 13) && i == 2))) {// 拾X元的特殊处理

							bits.add(new Bit(1, unit, hazPreZero, i, c.length()));
							hazPreZero = false;
						} else {
							if (unit == 0) {

							} else {
								if (unit == 1) {
									bits.add(new Bit(0, unit, hazPreZero, i, c.length()));
									hazPreZero = false;
								} else {
									throw new Exception("错误的大写金额格式，单位前必须有数字！");
								}
							}
						}
					} else {
						bits.add(new Bit(curNum, unit, hazPreZero, i, c.length()));
						hazPreZero = false;
					}
					curUnit = unit;
					curNum = null;
				}
			} else {
				Integer num = digitMap.get(c);
				if (num != null) {
					if (curNum != null) {
						throw new Exception("错误的大写金额格式，连续两个数字！");
					}
					curNum = num;
				}
				curUnit = null;
			}

		}
		// 对于万和亿前的千百升位：
		Integer curUnit4Shift = null;

		for (int i = bits.size() - 1; i >= 0; i--) {
			Bit bit = bits.get(i);
			if (bit.unit % 4 == 0) {
				if (curUnit4Shift == null) {
					curUnit4Shift = bit.unit;
				} else {
					if (bit.unit > curUnit4Shift) {
						curUnit4Shift = bit.unit;
					} else {
						if (curUnit4Shift == bit.unit) {
							throw new Exception("错误的大写金额格式:连续两个相同单位！");
						}
						curUnit4Shift = curUnit4Shift + bit.unit;

						bit.unit = curUnit4Shift;
					}
				}
			} else {
				if (curUnit4Shift != null && bit.unit < curUnit4Shift) {
					bit.unit += curUnit4Shift;
				}
				for (int k = 4; k < 60; k += 4)
					if (bit.unit > k) {
						if (curUnit4Shift == null || curUnit4Shift < k) {
							curUnit4Shift = k;
						}
					}
			}

		}
		// 检查必须有元：
		if (bits.size() > 0) {
			if (bits.get(0).unit > -1) {
				if (moneyCap.indexOf("元") == -1) {
					throw new Exception("错误的大写金额格式:必须有'元'字样！");
				}
			}
		}
		// 检查：
		for (int i = 1; i < bits.size(); i++) {
			Bit bit = bits.get(i);
			Bit bit2 = bits.get(i - 1);
			if (bit.unit > bit2.unit) {
				throw new Exception("错误的大写金额格式单位顺序错乱！");
			}

			int ii = bit.indexOf - bit.lenOfUnit - 1;
			if (bit2.unit - bit.unit > 1) {

				if (moneyCap.charAt(ii) != '零') {
					if ((bit2.unit % 4 != 1) && (bit.unit % 4 != 3) && bit.unit != -1) {

						throw new Exception("错误的大写金额格式," + ii + "位置缺乏零字样！");
					} else {
						if (bit.unit == -2) {
							throw new Exception("错误的大写金额格式," + ii + "位置缺乏零字样！");
						}
					}
				}
			} else {
				if (moneyCap.charAt(ii) == '零') {
					throw new Exception("错误的大写金额格式," + ii + "位置多零字样！");
				}
			}
		}
		// 无亿的不允许有两个万字样:
		if (bits.get(0).unit < 10) {

			int wanidx = moneyCap.indexOf("万");
			if (wanidx != -1) {
				if (moneyCap.indexOf("万", wanidx + 1) != -1) {
					throw new Exception("错误的大写金额格式:两个'万'字样");
				}
			}
		}
		// 对于跳位情况补0：


		List<Bit> bitZeroed = new ArrayList<Bit>();
		for (int i = 0; i < bits.size(); i++) {
			Bit bit = bits.get(i);
			bitZeroed.add(bit);
			if (i < bits.size() - 1) {
				Bit bit2 = bits.get(i + 1);
				if (bit.unit - bit2.unit > 1) {
					for (int j = 0; j < bit.unit - bit2.unit - 1; j++) {
						Bit bit3 = new Bit(0, bit.unit - j - 1, false, -1, 0);
						bitZeroed.add(bit3);
					}
				}
			}
		}
		// 拼写字符串：
		String ret = "";
		Bit last = null;
		for (int i = 0; i < bitZeroed.size(); i++) {
			Bit bit = bitZeroed.get(i);
			if (i > 0) {
				if (bit.unit == -1) {
					ret += ".";
				}
			} else {
				if (bit.unit == -1) {
					ret += ".";
				} else if (bit.unit == -2) {
					ret += ".0";
				}
			}
			last = bit;
			ret += bit.num;

		}
		if (last != null) {
			if (last.unit >= 0) {
				if (!moneyCap.endsWith("整") && !moneyCap.endsWith("正")) {
					throw new Exception("错误的大写金额格式，缺少'整'结束字！");
				}
			}
			for (int i = 0; i < last.unit; i++) {
				ret += "0";
			}
		}

		if (ret.length() == 0 && moneyCap.charAt(0) == '零') {
			if (!moneyCap.endsWith("整") && !moneyCap.endsWith("正")) {
				throw new Exception("错误的大写金额格式，缺少'整'结束字！");
			}
			return "0";
		} else {
			return ret;
		}
	}

	private static boolean isWholeMarkAtEnd(String moneyCap, int i, char charAt) {
		return ('正' == charAt || '整' == charAt) && i == moneyCap.length() - 1;
	}

	private static String[] invalidWords = new String[] { "分正", "分整", "零亿", "零万", "零千", "零百", "零仟", "零佰", "零零", "零角",
			"零元", "零分" };

	/**
	 * 单位表
	 */
	private static Map<String, Integer> unitMap;
	static {
		initUnitMap();
	}

	private static void initUnitMap() {
		unitMap = new java.util.LinkedHashMap<String, Integer>();
		if (supportSimpleChineseDig) {

			unitMap.put("千万亿", 15);
			unitMap.put("百万亿", 14);
			unitMap.put("十万亿", 13);

		}
		unitMap.put("仟万亿", 15);
		unitMap.put("佰万亿", 14);
		unitMap.put("拾万亿", 13);
		unitMap.put("仟万", 7);
		unitMap.put("佰万", 6);
		unitMap.put("拾万", 5);
		if (supportSimpleChineseDig) {
			unitMap.put("千万", 7);
			unitMap.put("百万", 6);
			unitMap.put("十万", 5);
		}
		if (supportSimpleChineseDig) {
			unitMap.put("千亿", 11);
			unitMap.put("百亿", 10);
			unitMap.put("十亿", 9);
		}
		unitMap.put("万亿", 12);
		unitMap.put("仟亿", 11);
		unitMap.put("佰亿", 10);
		unitMap.put("拾亿", 9);
		unitMap.put("亿", 8);
		unitMap.put("万", 4);
		unitMap.put("仟", 3);
		unitMap.put("佰", 2);
		unitMap.put("拾", 1);
		unitMap.put("元", 0);
		unitMap.put("角", -1);
		unitMap.put("分", -2);
		if (supportSimpleChineseDig) {
			unitMap.put("千", 3);
			unitMap.put("百", 2);
			unitMap.put("十", 1);
		}
		unitMap.put("圆", 0);
	}

	private static Map<String, Integer> digitMap;
	static {
		initDigitMap();
	}

	private static void initDigitMap() {
		digitMap = new LinkedHashMap<String, Integer>();
		if (supportSimpleChineseDig) {
			digitMap.put("一", 1);
			digitMap.put("二", 2);
			digitMap.put("三", 3);
			digitMap.put("四", 4);
			digitMap.put("五", 5);
			digitMap.put("六", 6);
			digitMap.put("七", 7);
			digitMap.put("八", 8);
			digitMap.put("九", 9);
		}
		digitMap.put("壹", 1);
		digitMap.put("贰", 2);
		digitMap.put("叁", 3);
		digitMap.put("肆", 4);
		digitMap.put("伍", 5);
		digitMap.put("陆", 6);
		digitMap.put("柒", 7);
		digitMap.put("捌", 8);
		digitMap.put("玖", 9);
	}

	private static List<String> marks;
	static {
		initMarks();
	}

	private static void initMarks() {
		marks = new ArrayList<String>();
		marks.addAll(unitMap.keySet());
		marks.addAll(digitMap.keySet());
	}

	static class Bit {

		Integer num;

		Integer unit;

		boolean hasPreZero;

		int indexOf;

		int lenOfUnit;

		public Bit(Integer num, Integer unit, boolean hasPreZero, int indexOf, int lenOfUnit) {
			super();
			this.num = num;
			this.unit = unit;
			this.hasPreZero = true;
			this.indexOf = indexOf;
			this.lenOfUnit = lenOfUnit;
		}

		public String toString() {
			return String.valueOf(num) + ":" + unit + ":" + hasPreZero + ":" + indexOf;
		}
	}

}
